home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / lkbackup.zip / ntpipe.c < prev    next >
C/C++ Source or Header  |  1993-09-29  |  20KB  |  906 lines

  1. // hacked this out of the NT port of Perl, which is copylefted by
  2. // Clark Williams of Intergraph Corp.
  3.  
  4. /*
  5.  *  Copyright (c) 1993, Intergraph Corporation
  6.  *
  7.  *  You may distribute under the terms of either the GNU General Public
  8.  *  License or the Artistic License, as specified in the perl README file.
  9.  *
  10.  *  Various Unix compatibility functions and NT specific functions.
  11.  *
  12.  *  Some of this code was derived from the MSDOS port(s) and the OS/2 port.
  13.  *
  14.  *  I pulled this out of the PERL NT port (the memory functions came
  15.  *  from PERL itself (v 4.036).  Clark Williams of Intergraph wrote
  16.  *  the original of this, and I apologize to him in advance for hacking
  17.  *  it all up.  :-)
  18.  *
  19.  */
  20.  
  21.  
  22. /* $Log: ntpipe.c,v $
  23.  * Revision 1.4  1993/09/16  21:16:31  ESullivan
  24.  * Added a function to get the pid from a process and a wait_for(pid)
  25.  * function.
  26.  *
  27.  * Revision 1.3  1993/09/16  01:10:14  ESullivan
  28.  * Added an $Id $ section.
  29.  *
  30.  * Revision 1.2  1993/09/07  02:09:30  ESullivan
  31.  * added a $Log area.
  32.  *
  33. */
  34.  
  35. char ntpipever[] = "$Id: ntpipe.c,v 1.4 1993/09/16 21:16:31 ESullivan Exp ESullivan $";
  36. #include "nt.h"
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <io.h>
  40. #include <fcntl.h>
  41. #include <process.h>
  42. #include <sys/stat.h>
  43. #include <assert.h>
  44. #include <errno.h>
  45.  
  46.  
  47. // popen stuff
  48.  
  49. //
  50. // use these so I can remember which index is which
  51. //
  52.  
  53. #define NtPipeRead  0       // index of pipe read descriptor
  54. #define NtPipeWrite 1       // index of pipe write descriptor
  55.  
  56. #define NtPipeSize  1024   // size of pipe buffer
  57.  
  58. #define MYPOPENSIZE 256       // size of book keeping structure
  59.  
  60. struct {
  61.     int inuse;
  62.     int pid;
  63.     FILE *pipe;
  64. } MyPopenRecord[MYPOPENSIZE];
  65.  
  66. FILE *
  67. ntpopen (char *cmd, char *mode) 
  68. {
  69.     FILE *fp;
  70.     int saved, reading;
  71.     int pipemode;
  72.     int pipes[2];
  73.     int pid;
  74.     int slot;
  75.     static initialized = 0;
  76.  
  77.     //
  78.     // if first time through, intialize our book keeping structure
  79.     //
  80.  
  81.     if (!initialized++) {
  82.     for (slot = 0; slot < MYPOPENSIZE; slot++)
  83.         MyPopenRecord[slot].inuse = FALSE;
  84.     }
  85.  
  86.     //
  87.     // find a free popen slot
  88.     //
  89.  
  90.     for (slot = 0; slot < MYPOPENSIZE && MyPopenRecord[slot].inuse; slot++)
  91.     ;
  92.  
  93.     if (slot > MYPOPENSIZE) {
  94.     return NULL;
  95.     }
  96.  
  97.     //
  98.     // Figure out what we\'re doing...
  99.     //
  100.  
  101.     reading = (*mode == 'r') ? TRUE : FALSE;
  102.     pipemode = (*(mode+1) == 'b') ? O_BINARY : O_TEXT;
  103.  
  104.     //
  105.     // Now get a pipe
  106.     //
  107.  
  108.     if (_pipe(pipes, NtPipeSize, pipemode) == -1) {
  109.     return NULL;
  110.     }
  111.  
  112.     if (reading) {
  113.  
  114.     //
  115.     // we\'re reading from the pipe, so we must hook up the
  116.     // write end of the pipe to the new processes stdout.
  117.     // To do this we must save our file handle from stdout
  118.     // by _dup\'ing it, then setting our stdout to be the pipe\'s 
  119.     // write descriptor. We must also make the write handle 
  120.     // inheritable so the new process can use it.
  121.  
  122.     if ((saved = _dup(fileno(stdout))) == -1) {
  123.         _close(pipes[NtPipeRead]);
  124.         _close(pipes[NtPipeWrite]);
  125.         return NULL;
  126.     }
  127.     if (_dup2 (pipes[NtPipeWrite], fileno(stdout)) == -1) {
  128.         _close(pipes[NtPipeRead]);
  129.         _close(pipes[NtPipeWrite]);
  130.         return NULL;
  131.     }
  132.     }
  133.     else {
  134.     //
  135.     // must be writing to the new process. Do the opposite of
  136.     // the above, i.e. hook up the processes stdin to the read
  137.     // end of the pipe.
  138.     //
  139.  
  140.     if ((saved = _dup(fileno(stdin))) == -1) {
  141.         _close(pipes[NtPipeRead]);
  142.         _close(pipes[NtPipeWrite]);
  143.         return NULL;
  144.     }
  145.     if (_dup2(pipes[NtPipeRead], fileno(stdin)) == -1) {
  146.         _close(pipes[NtPipeRead]);
  147.         _close(pipes[NtPipeWrite]);
  148.         return NULL;
  149.     }
  150.     }
  151.  
  152.     //
  153.     // Start the new process. Must set _fileinfo to non-zero value
  154.     // for file descriptors to be inherited. Reset after the process
  155.     // is started.
  156.     //
  157.  
  158.     if (NtHasRedirection(cmd)) {
  159.       docmd:
  160.     pid = spawnlpe(_P_NOWAIT, "cmd.exe", "/c", cmd, 0, environ);
  161.     if (pid == -1) {
  162.         _close(pipes[NtPipeRead]);
  163.         _close(pipes[NtPipeWrite]);
  164.         return NULL;
  165.     }
  166.     }
  167.     else {
  168.     char **vec;
  169.     int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
  170.  
  171.     pid = spawnvpe (_P_NOWAIT, vec[0], vec, environ);
  172.     if (pid == -1) {
  173.         goto docmd;
  174.     }
  175.     Safefree (vec);
  176.     }
  177.  
  178.     if (reading) {
  179.  
  180.     //
  181.     // We need to close our instance of the inherited pipe write
  182.     // handle now that it's been inherited so that it will actually close
  183.     // when the child process ends.
  184.     //
  185.  
  186.     if (_close(pipes[NtPipeWrite]) == -1) {
  187.         _close(pipes[NtPipeRead]);
  188.         return NULL;
  189.     }
  190.     if (_dup2 (saved, fileno(stdout)) == -1) {
  191.         _close(pipes[NtPipeRead]);
  192.         return NULL;
  193.     }
  194.     _close(saved);
  195.  
  196.     // 
  197.     // Now get a stream pointer to return to the calling program.
  198.     //
  199.  
  200.     if ((fp = (FILE *) fdopen(pipes[NtPipeRead], mode)) == NULL) {
  201.         return NULL;
  202.     }
  203.     }
  204.     else {
  205.  
  206.     //
  207.     // need to close our read end of the pipe so that it will go 
  208.     // away when the write end is closed.
  209.     //
  210.  
  211.     if (_close(pipes[NtPipeRead]) == -1) {
  212.         _close(pipes[NtPipeWrite]);
  213.         return NULL;
  214.     }
  215.     if (_dup2 (saved, fileno(stdin)) == -1) {
  216.         _close(pipes[NtPipeWrite]);
  217.         return NULL;
  218.     }
  219.     _close(saved);
  220.  
  221.     // 
  222.     // Now get a stream pointer to return to the calling program.
  223.     //
  224.  
  225.     if ((fp = (FILE *) fdopen(pipes[NtPipeWrite], mode)) == NULL) {
  226.         _close(pipes[NtPipeWrite]);
  227.         return NULL;
  228.     }
  229.     }
  230.  
  231.     //
  232.     // do the book keeping
  233.     //
  234.  
  235.     MyPopenRecord[slot].inuse = TRUE;
  236.     MyPopenRecord[slot].pipe = fp;
  237.     MyPopenRecord[slot].pid = pid;
  238.  
  239.     return fp;
  240. }
  241.  
  242. FILE *
  243. ntpopenEx (char *cmd, char *mode, int *cpipes) 
  244. {
  245.     FILE *fp;
  246.     int saved, reading;
  247.     int pipemode;
  248.     int pipes[2];
  249.     int pid;
  250.     int slot;
  251.     static initialized = 0;
  252.  
  253.     //
  254.     // if first time through, intialize our book keeping structure
  255.     //
  256.  
  257.     if (!initialized++) {
  258.     for (slot = 0; slot < MYPOPENSIZE; slot++)
  259.         MyPopenRecord[slot].inuse = FALSE;
  260.     }
  261.  
  262.     //
  263.     // find a free popen slot
  264.     //
  265.  
  266.     for (slot = 0; slot < MYPOPENSIZE && MyPopenRecord[slot].inuse; slot++)
  267.     ;
  268.  
  269.     if (slot > MYPOPENSIZE) {
  270.     return NULL;
  271.     }
  272.  
  273.     //
  274.     // Figure out what we\'re doing...
  275.     //
  276.  
  277.     reading = (*mode == 'r') ? TRUE : FALSE;
  278.     pipemode = (*(mode+1) == 'b') ? O_BINARY : O_TEXT;
  279.  
  280.     //
  281.     // Now get a pipe
  282.     //
  283.  
  284.     if (_pipe(pipes, NtPipeSize, pipemode) == -1) {
  285.     return NULL;
  286.     }
  287.  
  288.     cpipes[NtPipeRead] = pipes[NtPipeRead];
  289.     cpipes[NtPipeWrite] = pipes[NtPipeWrite];
  290.     if (reading) {
  291.  
  292.     //
  293.     // we\'re reading from the pipe, so we must hook up the
  294.     // write end of the pipe to the new processes stdout.
  295.     // To do this we must save our file handle from stdout
  296.     // by _dup\'ing it, then setting our stdout to be the pipe\'s 
  297.     // write descriptor. We must also make the write handle 
  298.     // inheritable so the new process can use it.
  299.  
  300.     if ((saved = _dup(fileno(stdout))) == -1) {
  301.         _close(pipes[NtPipeRead]);
  302.         _close(pipes[NtPipeWrite]);
  303.         return NULL;
  304.     }
  305.     if (_dup2 (pipes[NtPipeWrite], fileno(stdout)) == -1) {
  306.         _close(pipes[NtPipeRead]);
  307.         _close(pipes[NtPipeWrite]);
  308.         return NULL;
  309.     }
  310.     }
  311.     else {
  312.     //
  313.     // must be writing to the new process. Do the opposite of
  314.     // the above, i.e. hook up the processes stdin to the read
  315.     // end of the pipe.
  316.     //
  317.  
  318.     if ((saved = _dup(fileno(stdin))) == -1) {
  319.         _close(pipes[NtPipeRead]);
  320.         _close(pipes[NtPipeWrite]);
  321.         return NULL;
  322.     }
  323.     if (_dup2(pipes[NtPipeRead], fileno(stdin)) == -1) {
  324.         _close(pipes[NtPipeRead]);
  325.         _close(pipes[NtPipeWrite]);
  326.         return NULL;
  327.     }
  328.     }
  329.  
  330.     //
  331.     // Start the new process. Must set _fileinfo to non-zero value
  332.     // for file descriptors to be inherited. Reset after the process
  333.     // is started.
  334.     //
  335.  
  336.     if (NtHasRedirection(cmd)) {
  337.       docmd:
  338.     pid = spawnlpe(_P_NOWAIT, "cmd.exe", "/c", cmd, 0, environ);
  339.     if (pid == -1) {
  340.         _close(pipes[NtPipeRead]);
  341.         _close(pipes[NtPipeWrite]);
  342.         return NULL;
  343.     }
  344.     }
  345.     else {
  346.     char **vec;
  347.     int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
  348.  
  349.     pid = spawnvpe (_P_NOWAIT, vec[0], vec, environ);
  350.     if (pid == -1) {
  351.         goto docmd;
  352.     }
  353.     Safefree (vec);
  354.     }
  355.  
  356.     if (reading) {
  357.  
  358.  
  359.     // 
  360.     // Now get a stream pointer to return to the calling program.
  361.     //
  362.  
  363.     if ((fp = (FILE *) fdopen(pipes[NtPipeRead], mode)) == NULL) {
  364.         return NULL;
  365.     }
  366.     }
  367.     else {
  368.  
  369.  
  370.     // 
  371.     // Now get a stream pointer to return to the calling program.
  372.     //
  373.  
  374.     if ((fp = (FILE *) fdopen(pipes[NtPipeWrite], mode)) == NULL) {
  375.         _close(pipes[NtPipeWrite]);
  376.         return NULL;
  377.     }
  378.     }
  379.  
  380.     //
  381.     // do the book keeping
  382.     //
  383.  
  384.     MyPopenRecord[slot].inuse = TRUE;
  385.     MyPopenRecord[slot].pipe = fp;
  386.     MyPopenRecord[slot].pid = pid;
  387.     cpipes[NtPipeRead] = pipes[NtPipeRead];
  388.     cpipes[NtPipeWrite] = pipes[NtPipeWrite];
  389.  
  390.     return fp;
  391. }
  392.  
  393. int
  394. ntpclose(FILE *fp)
  395. {
  396.     int i;
  397.     int exitcode;
  398.  
  399.     for (i = 0; i < MYPOPENSIZE; i++) {
  400.     if (MyPopenRecord[i].inuse && MyPopenRecord[i].pipe == fp)
  401.         break;
  402.     }
  403.     if (i >= MYPOPENSIZE) {
  404.     fprintf(stderr,"Invalid file pointer passed to mypclose!\n");
  405.     abort();
  406.     }
  407.  
  408.     //
  409.     // get the return status of the process
  410.     //
  411.  
  412.     if (_cwait(&exitcode, MyPopenRecord[i].pid, WAIT_CHILD) == -1) {
  413.     if (errno == ECHILD) {
  414.         fprintf(stderr, "mypclose: nosuch child as pid %x\n", 
  415.             MyPopenRecord[i].pid);
  416.     }
  417.     }
  418.  
  419.     //
  420.     // close the pipe
  421.     //
  422.  
  423.     fclose(fp);
  424.  
  425.     //
  426.     // free this slot
  427.     //
  428.  
  429.     MyPopenRecord[i].inuse = FALSE;
  430.  
  431.     return exitcode;
  432. }
  433.  
  434. /*
  435.  * The following code is based on the do_exec and do_aexec functions
  436.  * in file doio.c
  437.  */
  438.  
  439.  
  440. typedef struct _NtCmdLineElement {
  441.     struct _NtCmdLineElement *next, *prev;
  442.     char *str;
  443.     int len;
  444.     int flags;
  445. } NtCmdLineElement;
  446.  
  447. //
  448. // Possible values for flags
  449. //
  450.  
  451. #define NTGLOB   0x1    // element contains a wildcard
  452. #define NTMALLOC 0x2    // string in element was malloc'ed
  453. #define NTSTRING 0x4    // element contains a quoted string
  454.  
  455. NtCmdLineElement *NtCmdHead = NULL, *NtCmdTail = NULL;
  456.  
  457. void
  458. NtFreeCmdLine(void)
  459. {
  460.     NtCmdLineElement *ptr;
  461.     
  462.     while(NtCmdHead) {
  463.     ptr = NtCmdHead;
  464.     NtCmdHead = NtCmdHead->next;
  465.     Safefree(ptr);
  466.     }
  467.     NtCmdHead = NtCmdTail = NULL;
  468. }
  469.  
  470. //
  471. // This function expands wild card characters that were spotted 
  472. // during the parse phase. The idea here is to call FindFirstFile and
  473. // FindNextFile with the wildcard pattern specified, and splice in the
  474. // resulting list of new names. If the wildcard pattern doesn\'t match 
  475. // any existing files, just leave it in the list.
  476. //
  477.  
  478. void
  479. NtCmdGlob (NtCmdLineElement *patt)
  480. {
  481.     WIN32_FIND_DATA fd;
  482.     HANDLE fh;
  483.     char buffer[512];
  484.     NtCmdLineElement *tmphead, *tmptail, *tmpcurr;
  485.  
  486.     strncpy(buffer, patt->str, patt->len);
  487.     buffer[patt->len] = '\0';
  488.     if ((fh = FindFirstFile (buffer, &fd)) == INVALID_HANDLE_VALUE) {
  489.     return;
  490.     }
  491.     tmphead = tmptail = NULL;
  492.     do {
  493.     New (1301, tmpcurr, 1 , NtCmdLineElement);
  494.     if (tmpcurr == NULL) {
  495.         fprintf(stderr, "Out of Memory in globbing!\n");
  496.         while (tmphead) {
  497.         tmpcurr = tmphead;
  498.         tmphead = tmphead->next;
  499.         Safefree(tmpcurr->str);
  500.         Safefree(tmpcurr);
  501.         }
  502.         return;
  503.     }
  504.     memset (tmpcurr, 0, sizeof(*tmpcurr));
  505.     tmpcurr->len = strlen(fd.cFileName);
  506.     New(1301, tmpcurr->str, tmpcurr->len+1, char);
  507.     if (tmpcurr->str == NULL) {
  508.         fprintf(stderr, "Out of Memory in globbing!\n");
  509.         while (tmphead) {
  510.         tmpcurr = tmphead;
  511.         tmphead = tmphead->next;
  512.         Safefree(tmpcurr->str);
  513.         Safefree(tmpcurr);
  514.         }
  515.         return;
  516.     }
  517.     strcpy(tmpcurr->str, fd.cFileName);
  518.     tmpcurr->flags |= NTMALLOC;
  519.     if (tmptail) {
  520.         tmptail->next = tmpcurr;
  521.         tmpcurr->prev = tmptail;
  522.         tmptail = tmpcurr;
  523.     }
  524.     else {
  525.         tmptail = tmphead = tmpcurr;
  526.     }
  527.     } while(FindNextFile(fh, &fd));
  528.  
  529.     //
  530.     // ok, now we\'ve got a list of files that matched the wildcard
  531.     // specification. Put it in place of the pattern structure.
  532.     //
  533.     
  534.     tmphead->prev = patt->prev;
  535.     tmptail->next = patt->next;
  536.  
  537.     if (tmphead->prev)
  538.     tmphead->prev->next = tmphead;
  539.  
  540.     if (tmptail->next)
  541.     tmptail->next->prev = tmptail;
  542.  
  543.     //
  544.     // Now get rid of the pattern structure
  545.     //
  546.  
  547.     if (patt->flags & NTMALLOC)
  548.     Safefree(patt->str);
  549.     Safefree(patt);
  550. }
  551.  
  552. // 
  553. // Check a command string to determine if it has I/O redirection
  554. // characters that require it to be executed by a command interpreter
  555. //
  556.  
  557. bool
  558. NtHasRedirection (char *cmd)
  559. {
  560.     int inquote = 0;
  561.     char quote = '\0';
  562.     char *ptr ;
  563.     
  564.     //
  565.     // Scan the string, looking for redirection (< or >) or pipe 
  566.     // characters (|) that are not in a quoted string
  567.     //
  568.  
  569.     for (ptr = cmd; *ptr; ptr++) {
  570.  
  571.     switch (*ptr) {
  572.  
  573.       case '\'':
  574.       case '\"':
  575.         if (inquote) {
  576.         if (quote == *ptr) {
  577.             inquote = 0;
  578.             quote = '\0';
  579.         }
  580.         }
  581.         else {
  582.         quote = *ptr;
  583.         inquote++;
  584.         }
  585.         break;
  586.  
  587.       case '>':
  588.       case '<':
  589.  
  590.         if (!inquote)
  591.         return TRUE;
  592.     }
  593.     }
  594.     return FALSE;
  595. }
  596.  
  597.  
  598. int 
  599. NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
  600. {
  601.     int cmdlen = strlen(cmdline);
  602.     int done, instring, globbing, quoted, len;
  603.     int newline, need_free = 0, i;
  604.     int elements, strsz;
  605.     int slashes = 0;
  606.     char *ptr, *base, *buffer;
  607.     char **vptr;
  608.     char quote;
  609.     NtCmdLineElement *curr;
  610.  
  611.     //
  612.     // just return if we don\'t have a command line
  613.     //
  614.  
  615.     if (cmdlen == 0) {
  616.     *vec = NULL;
  617.     return 0;
  618.     }
  619.  
  620.     //
  621.     // strip trailing white space
  622.     //
  623.  
  624.     ptr = cmdline+(cmdlen - 1);
  625.     while(ptr >= cmdline && isspace(*ptr))
  626.         --ptr;
  627.     *++ptr = '\0';
  628.  
  629.     //
  630.     // check for newlines and formfeeds. If we find any, make a new
  631.     // command string that replaces them with escaped sequences (\n or \f)
  632.     //
  633.  
  634.     for (ptr = cmdline, newline = 0; *ptr; ptr++) {
  635.     if (*ptr == '\n' || *ptr == '\f')
  636.         newline++;
  637.     }
  638.  
  639.     if (newline) {
  640.     New (1200, base, strlen(cmdline) + 1 + newline + slashes, char);
  641.     if (base == NULL) {
  642.         fprintf(stderr, "malloc failed!\n");
  643.         return 0;
  644.     }
  645.     for (i = 0, ptr = base; (unsigned) i < strlen(cmdline); i++) {
  646.         switch (cmdline[i]) {
  647.           case '\n':
  648.         *ptr++ = '\\';
  649.         *ptr++ = 'n';
  650.         break;
  651.           default:
  652.         *ptr++ = cmdline[i];
  653.         }
  654.     }
  655.     *ptr = '\0';
  656.     cmdline = base;
  657.     need_free++;
  658.     }
  659.  
  660.     //
  661.     // Ok, parse the command line, building a list of CmdLineElements.
  662.     // When we\'ve finished, and it\'s an input command (meaning that it\'s
  663.     // the processes argv), we\'ll do globing and then build the argument 
  664.     // vector.
  665.     // The outer loop does one interation for each element seen. 
  666.     // The inner loop does one interation for each character in the element.
  667.     //
  668.  
  669.     for (done = 0, ptr = cmdline; *ptr;) {
  670.  
  671.     //
  672.     // zap any leading whitespace
  673.     //
  674.  
  675.     while(isspace(*ptr))
  676.         ptr++;
  677.     base = ptr;
  678.  
  679.     for (done = newline = globbing = instring = quoted = 0; 
  680.          *ptr && !done; ptr++) {
  681.  
  682.         //
  683.         // Switch on the current character. We only care about the
  684.         // white-space characters, the  wild-card characters, and the
  685.         // quote characters.
  686.         //
  687.  
  688.         switch (*ptr) {
  689.           case ' ':
  690.           case '\t':
  691. #if 0
  692.           case '/':  // have to do this for NT/DOS option strings
  693.  
  694.         //
  695.         // check to see if we\'re parsing an option switch
  696.         //
  697.  
  698.         if (*ptr == '/' && base == ptr)
  699.             continue;
  700. #endif
  701.         //
  702.         // if we\'re not in a string, then we\'re finished with this
  703.         // element
  704.         //
  705.  
  706.         if (!instring)
  707.             done++;
  708.         break;
  709.  
  710.           case '*':
  711.           case '?':
  712.  
  713.         // 
  714.         // record the fact that this element has a wildcard character
  715.         // N.B. Don\'t glob if inside a single quoted string
  716.         //
  717.  
  718.         if (!(instring && quote == '\''))
  719.             globbing++;
  720.         break;
  721.  
  722.           case '\n':
  723.  
  724.         //
  725.         // If this string contains a newline, mark it as such so
  726.         // we can replace it with the two character sequence "\n"
  727.         // (cmd.exe doesn\'t like raw newlines in strings...sigh).
  728.         //
  729.  
  730.         newline++;
  731.         break;
  732.  
  733.           case '\'':
  734.           case '\"':
  735.  
  736.         //
  737.         // if we\'re already in a string, see if this is the
  738.         // terminating close-quote. If it is, we\'re finished with 
  739.         // the string, but not neccessarily with the element.
  740.         // If we\'re not already in a string, start one.
  741.         //
  742.  
  743.         if (instring) {
  744.             if (quote == *ptr) {
  745.             instring = 0;
  746.             quote = '\0';
  747.             }
  748.         }
  749.         else {
  750.             instring++;
  751.             quote = *ptr;
  752.             quoted++;
  753.         }
  754.         break;
  755.         }
  756.     }
  757.  
  758.     //
  759.     // need to back up ptr by one due to last increment of for loop
  760.     // (if we got out by seeing white space)
  761.     //
  762.  
  763.     if (*ptr)
  764.         ptr--;
  765.  
  766.     //
  767.     // when we get here, we\'ve got a pair of pointers to the element,
  768.     // base and ptr. Base points to the start of the element while ptr
  769.     // points to the character following the element.
  770.     //
  771.  
  772.     New (1201, curr, 1, NtCmdLineElement);
  773.     if (curr == NULL) {
  774.         NtFreeCmdLine();
  775.         fprintf(stderr, "Out of memory!!\n");
  776.         *vec = NULL;
  777.         return 0;
  778.     }
  779.     memset (curr, 0, sizeof(*curr));
  780.  
  781.     len = ptr - base;
  782.  
  783.     //
  784.     // if it\'s an input vector element and it\'s enclosed by quotes, 
  785.     // we can remove them.
  786.     //
  787.  
  788.     if (InputCmd &&
  789.         ((base[0] == '\"' && base[len-1] == '\"') ||
  790.          (base[0] == '\'' && base[len-1] == '\''))) {
  791.         base++;
  792.         len -= 2;
  793.     }
  794.  
  795.     curr->str = base;
  796.     curr->len = len;
  797.     curr->flags |= (globbing ? NTGLOB : 0);
  798.  
  799.     //
  800.     // Now put it in the list of elements
  801.     //
  802.     if (NtCmdTail) {
  803.         NtCmdTail->next = curr;
  804.         curr->prev = NtCmdTail;
  805.         NtCmdTail = curr;
  806.     }
  807.     else {
  808.         NtCmdHead = NtCmdTail = curr;
  809.     }
  810.     }
  811.  
  812.     if (InputCmd) {
  813.  
  814.     //
  815.     // When we get here we\'ve finished parsing the command line. Now 
  816.     // we need to run the list, expanding any globbing patterns.
  817.     //
  818.     
  819.     for(curr = NtCmdHead; curr; curr = curr->next) {
  820.         if (curr->flags & NTGLOB) {
  821.         NtCmdGlob(curr);
  822.         }
  823.     }
  824.     }
  825.  
  826.     //
  827.     // Almost done! 
  828.     // Count up the elements, then allocate space for a vector of pointers
  829.     // (argv) and a string table for the elements.
  830.     // 
  831.  
  832.     for (elements = 0, strsz = 0, curr = NtCmdHead; curr; curr = curr->next) {
  833.     elements++;
  834.     strsz += (curr->len + 1);
  835.     }
  836.  
  837.     len = (elements+1)*sizeof(char *) + strsz;
  838.     New (1202, buffer, len, char);
  839.     if (buffer == NULL) {
  840.     fprintf(stderr, "Out of memory!!\n");
  841.     NtFreeCmdLine();
  842.     *vec = NULL;
  843.     return 0;
  844.     }
  845.     
  846.     memset (buffer, 0, len);
  847.  
  848.     //
  849.     // make vptr point to the start of the buffer
  850.     // and ptr point to the area we\'ll consider the string table.
  851.     //
  852.  
  853.     vptr = (char **) buffer;
  854.  
  855.     ptr = buffer + (elements+1) * sizeof(char *);
  856.  
  857.     for (curr =  NtCmdHead; curr;  curr = curr->next) {
  858.     strncpy (ptr, curr->str, curr->len);
  859.     ptr[curr->len] = '\0';
  860.     *vptr++ = ptr;
  861.     ptr += curr->len + 1;
  862.     }
  863.     NtFreeCmdLine();
  864.     *vec = (char **) buffer;
  865.     return elements;
  866. }
  867.  
  868.  
  869. // added this function because I needed to get the pid
  870. int ntGetPid( FILE *fp)
  871. {
  872.     int i;
  873.  
  874.     for (i = 0; i < MYPOPENSIZE; i++) {
  875.     if (MyPopenRecord[i].inuse && MyPopenRecord[i].pipe == fp)
  876.         break;
  877.     }
  878.     if (i >= MYPOPENSIZE) {
  879.     fprintf(stderr,"Invalid file pointer passed to ntpclose!\n");
  880.     abort();
  881.     }
  882.     else
  883.     {
  884.         return MyPopenRecord[i].pid;
  885.     }
  886. }
  887.  
  888. int ntwait_for( int pid)
  889. {
  890.     int i;
  891.     // int exitcode;
  892.  
  893.     for (i = 0; i < MYPOPENSIZE; i++) {
  894.     if (MyPopenRecord[i].inuse && MyPopenRecord[i].pid == pid)
  895.         break;
  896.     }
  897.     if (i >= MYPOPENSIZE) {
  898.     fprintf(stderr,"Invalid pid passed to ntwait_for!\n");
  899.     abort();
  900.     }
  901.     else {
  902.         return ntpclose( MyPopenRecord[i].pipe);
  903.     }
  904. }
  905.     
  906.